import os,sys
sys.path.append(os.getcwd())
import tempfile
from flask import Flask
from flask.testing import FlaskClient, FlaskCliRunner
from werkzeug.test import TestResponse

import pytest
# Pytest通过匹配固件函数名称和测试函数的参数名称来使用固件.例如test_factory.py要写test_hello函数有一个client参数.Pytest会匹配client固件函数,调用该函数,把返回值传递给测试函数.
from flaskr import create_app
from flaskr.db import get_db, init_db

with open(os.path.join(os.path.dirname(__file__), 'data.sql'), 'rb') as f:
    _data_sql = f.read().decode('utf8')


@pytest.fixture
def app() -> Flask:
    db_fd, db_path = tempfile.mkstemp()
    # tempfile.mkstemp() 创建并打开一个临时文件,返回该文件对象和路径.

    app = create_app({
        'TESTING': True,
        # TESTING 告诉Flask应用处在测试模式下.Flask会改变一些内部行为以方便测试.其他的扩展也可以使用这个标志方便测试.
        'DATABASE': db_path,
        # DATABASE 路径被重载,这样它会指向临时路径,而不是实例文件夹.
    })

    with app.app_context():
        init_db()
        get_db().executescript(_data_sql)
        # 设置好路径之后,数据库表被创建,然后插入数据.

    yield app

    os.close(db_fd)
    os.unlink(db_path)
    # 测试结束后,临时文件会被关闭并删除.


@pytest.fixture
def client(app:Flask) -> FlaskClient:
    return app.test_client()
    # client 固件调用 app.test_client() 由 app 固件创建的应用对象.测试会使用客户端来向应用发送请求,而不用启动服务器.


@pytest.fixture
def runner(app:Flask) -> FlaskCliRunner:
    return app.test_cli_runner()
    # runner固件类似于client. app.test_cli_runner()创建一个运行器,可以调用应用注册的Click命令.

class AuthActions(object):
    def __init__(self, client:FlaskClient):
        self._client = client

    def login(self, username='test', password='test') -> TestResponse:
        return self._client.post(
            '/auth/login',
            data={'username': username, 'password': password}
        )

    def logout(self) -> TestResponse:
        return self._client.get('/auth/logout')

# 通过 auth 固件，可以在调试中调用 auth.login() 登录为 test 用户。这个用户的数据已经在 app 固件中写入了数据。
@pytest.fixture
def auth(client:FlaskClient) -> AuthActions:
    return AuthActions(client)

